package com.projet.word;

import cn.hutool.core.collection.CollectionUtil;
import com.core.common.IoUtils;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ReplaceWordUtil {

    //开始符
    private static final String VAR_BEGIN = "${";
    //结束符
    private static final String VAR_END = "}";
    //换行符号
    private static final String BR = "<####BrrB##>";

    /**
     * 替换文本
     *
     * @param inFile  输入文件
     * @param outFile 输出流
     * @param params  参数
     * @throws Exception
     */
    public static File changeText(File inFile, File outFile, List<WordParam> params) throws Exception {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream(inFile);
            if (outFile.exists()) {
                outFile.setWritable(true);
                outFile.setReadable(true);
                outFile.delete();
            }
            out = new FileOutputStream(outFile);
            ReplaceWordUtil.changeTextDocx(in, out, params);
            out.flush();
            out.close();
            return outFile;
        } finally {
            IoUtils.close(in, out);
        }
    }


    /**
     * 替换文本
     *
     * @param in     输入流
     * @param out    输出流
     * @param params 参数
     * @return 是否成功
     * @throws Exception
     */
    private static Boolean changeTextDocx(InputStream in, OutputStream out, List<WordParam> params) throws Exception {
        XWPFDocument document = null;
        try {
            document = new XWPFDocument(in);
            //替换自然段
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            if (!CollectionUtil.isEmpty(paragraphs)) {
                changeParagraphs(paragraphs, params);
            }
            //替换表格
            List<XWPFTable> tables = document.getTables();
            if (!CollectionUtil.isEmpty(tables)) {
                XWPFTableRow row;
                int count;
                List<XWPFTableCell> cells;
                for (XWPFTable table : tables) {
                    //获取table的行数
                    count = table.getNumberOfRows();
                    for (int i = 0; i < count; i++) {
                        row = table.getRow(i);
                        cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            changeParagraphs(cell.getParagraphs(), params);
                        }
                    }
                }
            }
            document.write(out);
        } finally {
            IoUtils.close(document);
        }
        return true;
    }

    /**
     * 替换文本
     *
     * @param paragraphs 段
     * @param params     待写入字符map
     */
    public static Boolean changeParagraphs(List<XWPFParagraph> paragraphs, List<WordParam> params) {
        if (CollectionUtil.isEmpty(paragraphs)) {
            return false;
        }
        String[] values;
        for (XWPFParagraph paragraph : paragraphs) {
            String text = paragraph.getText();
            if (text == null || text.length() == 0) {
                continue;
            }
            if (!text.contains(VAR_BEGIN)) {
                continue;
            }
            List<XWPFRun> runs = paragraph.getRuns();
            XWPFRun run;
            //注意 ${标签} 这个标签的font和size，颜色必须完全统一，要不XWPFRun不会在一个里面，最好主动设置一下
            Map<Integer, String> msgMap = new HashMap<>();
            for (int i = 0; i < runs.size(); i++) {
                msgMap.put(i, runs.get(i).toString());
            }
            String currentTxt;
            String nextTxt;
            for (int i = 0; i < runs.size(); i++) {
                currentTxt = msgMap.get(i);
                if (!isOk(currentTxt)) {
                    for (int j = i + 1; j < runs.size(); j++) {
                        nextTxt = msgMap.get(j);
                        if (nextTxt == null) {
                            nextTxt = "";
                        }
                        msgMap.put(j, "");
                        currentTxt += nextTxt;
                        msgMap.put(i, currentTxt);
                        if (isOk(currentTxt)) {
                            break;
                        }
                    }

                }
            }
            for (int i = 0; i < runs.size(); i++) {
                run = runs.get(i);
                currentTxt = msgMap.get(i);
                if (currentTxt.length() > 3 && currentTxt.indexOf(VAR_BEGIN) >= 0) {
                    values = replaceText(currentTxt, params);
                    for (int i1 = 0; i1 < values.length; i1++) {
                        if (i1 > 0) {
                            run.addBreak();
                        }
                        run.setText(values[i1], i1);
                    }
                } else {
                    run.setText(currentTxt, 0);
                }
            }
        }
        return true;
    }

    /**
     * 是否闭合
     *
     * @param txt
     * @return
     * @throws Exception
     */
    private static boolean isOk(String txt) {
        int b;
        int e;
        int start = 0;
        while (true) {
            //这里不能多个字符，因为可能多个字符也分成多段，那样就合并不了
            b = txt.indexOf("$", start);
            if (b < 0) {
                return true;
            }
            e = txt.indexOf(VAR_END, b + 1);
            if (e < 0) {
                return false;
            }
            start = e + 1;
        }
    }

    /**
     * 匹配传入信息集合与模板
     *
     * @param inText 模板需要替换的区域
     * @param params 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static String[] replaceText(String inText, List<WordParam> params) {
        String key;
        String value;
        String text = inText;
        for (WordParam param : params) {
            key = VAR_BEGIN + param.getKey() + VAR_END;
            if (text.indexOf(key) != -1) {
                value = param.getContent();
                if (value == null) {
                    value = "";
                } else {
                    // 替换参数的换行符
                    value = value.replaceAll("\r\n", "\n")
                            .replaceAll("\r", "\n")
                            .replaceAll("\n", BR);
                }
                text = text.replace(key, value);
            }
        }
        return text.split(BR);
    }
}
